/**
 * Copyright (c) 2016-2019, Michael Yang 杨福海 (fuhai999@gmail.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.hg.jfsa.web.theme;

import cn.hg.base.common.BaseConstants;
import cn.hg.base.kit.StrExtKit;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.Prop;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

public class Theme {

	private static Log log = Log.getLog(Theme.class);

	private String id;
	private String title;
	private String description;
	private String author;
	private String authorWebsite;
	private String version;
	private int versionCode;
	private String updateUrl;
	private String folder;
	private List<String> screenshots;
	private String optionsFile;
	private String optionsPage;

	private Properties propertis = new Properties();

	private List<String> htmls = new ArrayList<>();

	private Map<Integer, String> errorViewMap = new HashMap<>();

	private Theme() {

	}

	public Theme(String configFilePath) {

		File configFile = new File(configFilePath);
		Prop prop = new Prop(configFile, "utf-8");

		this.folder = configFile.getParentFile().getName();

		this.id = prop.get("id");
		this.title = prop.get("title");
		this.description = prop.get("description");
		this.author = prop.get("author");
		this.authorWebsite = prop.get("authorWebsite");
		this.version = prop.get("version");
		this.updateUrl = prop.get("updateUrl");
		this.screenshots = new ArrayList<>();
		this.optionsFile = prop.get("optionsFile");
		this.optionsPage = prop.get("optionsPage");

		if (StrKit.notBlank(prop.get("screenshots"))) {
			String[] scrs = prop.get("screenshots").split(",");
			for (String s : scrs) {
				this.screenshots.add(getWebAbsolutePath() + "/" + s);
			}
		}

		// 从主题的配置文件中读取错误页面信息
		String error401view = prop.get("error401view");
		if (StrKit.notBlank(error401view)) this.errorViewMap.put(401, error401view);
		String error403view = prop.get("error403view");
		if (StrKit.notBlank(error403view)) this.errorViewMap.put(403, error403view);
		String error404view = prop.get("error404view");
		if (StrKit.notBlank(error404view)) this.errorViewMap.put(404, error404view);
		String error500view = prop.get("error500view");
		if (StrKit.notBlank(error500view)) this.errorViewMap.put(500, error500view);
		String errorView = prop.get("errorView");
		if (StrKit.notBlank(error401view)) this.errorViewMap.put(0, errorView);

		String vcode = prop.get("versionCode");
		this.versionCode = StrExtKit.isBlank(vcode) ? 1 : Integer.valueOf(vcode);

		// 如果存在配置文件，则从配置文件中读取信息，配置文件为Properties格式
		if (StrKit.notBlank(this.optionsFile)) {
			try {
				propertis.load(new FileReader(this.getAbsolutePath() + this.optionsFile));
			} catch (IOException e) {
				log.error("主题加载错误：", e);
			}
		}

		String[] files = configFile
				.getParentFile()
				.list((dir, name) -> name.endsWith(".html"));

		htmls.addAll(Arrays.asList(files));
	}

	private static final String THEME_SEPARATOR = "_";
	private static final String THEME_H5_SUFFIX = "_h5.html";

	/**
	 * 找出可以用来渲染的 html 模板
	 *
	 * @param theme
	 * @return
	 */
	public String matchThemeFile(String theme, boolean isMoblieBrowser) {

		if (isMoblieBrowser) {
			int indexOf = theme.indexOf(".");
			theme = theme.substring(0, indexOf) + THEME_H5_SUFFIX;
		}

		if (htmls.contains(theme)) {
			return theme;
		}

		int lastIndex = theme.lastIndexOf(THEME_SEPARATOR);
		if (lastIndex <= 0) {
			return null;
		}

		//手机浏览器，优先去找_h5的模板进行渲染
		if (isMoblieBrowser) {
			String h5Theme = matchH5Theme(theme);
			if (h5Theme != null) return h5Theme;
		}

		while (lastIndex > 0) {
			theme = theme.substring(0, lastIndex) + ".html";
			if (htmls.contains(theme)) {
				return theme;
			}
			lastIndex = theme.lastIndexOf(THEME_SEPARATOR);
		}

		return htmls.contains(theme) ? theme : null;
	}


	/**
	 * 只匹配 h5 的模板 ，如果匹配不到 h5 ，返回 null
	 * <p>
	 * 例如：
	 * 需要 aa_bb_cc_dd_h5.html
	 * 寻找的顺序是：aa_bb_cc_h5.html  ->   aa_bb_h5.html  ->   aa_h5.html
	 *
	 * @param theme
	 * @return
	 */
	private String matchH5Theme(String theme) {

		// TODO:
//        while (StrExtKit.countMatches(theme, '_') > 1) {
//
//            int sLastIndex = StrExtKit.lastOrdinalIndexOf(theme, "_", 2);
//            theme = theme.substring(0, sLastIndex) + "_h5.html";
//
//            if (htmls.contains(theme)) {
//                return theme;
//            }
//        }

		return htmls.contains(theme) ? theme : null;
	}


	public String getId() {
		return id;
	}

	public String getTitle() {
		return title;
	}

	public String getDescription() {
		return description;
	}

	public String getAuthor() {
		return author;
	}

	public String getAuthorWebsite() {
		return authorWebsite;
	}

	public String getVersion() {
		return version;
	}

	public int getVersionCode() {
		return versionCode;
	}

	public String getUpdateUrl() {
		return updateUrl;
	}

	public String getFolder() {
		return folder;
	}

	void setFolder(String folder) {
		this.folder = folder;
	}

	public String getAbsolutePath() {
		return PathKit.getWebRootPath() + BaseConstants.THEME_PATH + "/" + folder;
	}

	public String getWebAbsolutePath() {
		return BaseConstants.THEME_PATH + "/" + folder;
	}

	public List<String> getScreenshots() {
		return screenshots;
	}

	public Map<Integer, String> getErrorViewMap() {
		return errorViewMap;
	}

	public String getOptionsFile() {
		return optionsFile;
	}

	public String getOptionsPage() {
		return optionsPage;
	}

	public String getOption(String key) {
		return this.propertis.getProperty(key);
	}

	void updateOptions(Map<String, String> optionMap) {
		if (StrKit.isBlank(this.getOptionsFile())) return;
		// 更新参数表
		this.propertis.putAll(optionMap);

		// 更新Options文件
		String optionFileName = this.getAbsolutePath() + this.getOptionsFile();
		File of = new File(optionFileName);
		FileWriter fw = null;
		if (of.exists() && of.isFile()) {
			try {
				fw = new FileWriter(of);
				this.propertis.store(fw, this.getTitle() + "：参数配置");
			} catch (IOException e) {
				log.warn("更新主题参数出错！", e);
			} finally {
				if (fw != null) {
					try {
						fw.close();
					} catch (IOException e) {
						log.warn("更新主题参数出错！", e);
					}
				}
			}
		}
	}
}
